{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "source": [
    "[this doc on github](https://github.com/dotnet/interactive/tree/main/samples/notebooks/polyglot)\n",
    "\n",
    "# using d3js to create widgets\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "source": [
    "Introducing a new command to push data to the js kernel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "using Microsoft.DotNet.Interactive;\n",
    "using Microsoft.DotNet.Interactive.Commands;\n",
    "\n",
    "public class WidgetData : KernelCommand {\n",
    "\n",
    "    public int[]  Data {get;set;}\n",
    "    public WidgetData(string targetKernelName = null) : base(targetKernelName?? \"javascript\") {\n",
    "\n",
    "    }\n",
    "}"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "source": [
    "register the command for serialization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var jsKernel = Kernel.Root.FindKernelByName(\"javascript\");\n",
    "jsKernel.RegisterCommandType<WidgetData>();"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "source": [
    "load 3djs using import"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "outputs": [],
   "source": [
    "d3 = await import(\"https://cdn.jsdelivr.net/npm/d3@7/+esm\");"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "source": [
    "adding the handler to the `javascript` kernel, this will use `d3js` to refresh the display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "outputs": [],
   "source": [
    "let jskernel = kernel.root.findKernelByName('javascript');\n",
    "\n",
    "jskernel.registerCommandHandler({commandType: 'WidgetData', handle: c => {\n",
    "\n",
    "    const svg = d3.select(\"#d3_target\");\n",
    "    const data = c.commandEnvelope.command.data;\n",
    "    const scaleFactor = 0.9;\n",
    "    const container = svg.select(\".container\");\n",
    "    const colorMap = (d) =>  d3.interpolateWarm(d / 80);\n",
    "    const p = container.selectAll(\".points\")\n",
    "        .data(data, (d, i) => i);\n",
    "\n",
    "    p.transition()\n",
    "        .duration(2000)\n",
    "        .style(\"fill\", d => colorMap(d))\n",
    "        .attr(\"r\", d => Math.max(0, d * scaleFactor));\n",
    "\n",
    "    p.enter()\n",
    "        .append(\"circle\")\n",
    "        .attr(\"class\", \"points\")\n",
    "        .attr(\"cy\", 80)\n",
    "        .attr(\"cx\", (d,i) => ((i) + 1) * 60)\n",
    "        .transition()\n",
    "        .duration(2000)\n",
    "        .style(\"fill\", d => colorMap(d))\n",
    "        .ease(d3.easeElasticOut.period(1.00))\n",
    "        .attr(\"r\", d => Math.max(0, d * scaleFactor)),\n",
    "\n",
    "    p.exit()\n",
    "        .transition()\n",
    "        .duration(1000)\n",
    "        .attr(\"r\", 0)\n",
    "        .remove();\n",
    "}});"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "source": [
    "add the html placeholder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "dotnet_interactive": {
     "language": "html"
    },
    "polyglot_notebook": {
     "kernelName": "html"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<svg id=\"d3_target\" style=\"width:100%;\"></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "<svg id=\"d3_target\" style=\"width:100%;\"></svg>"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "html"
    },
    "polyglot_notebook": {
     "kernelName": "html"
    }
   },
   "source": [
    "setup the svg container with some svg effects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "outputs": [],
   "source": [
    "const svg = d3.select(\"#d3_target\");\n",
    "\n",
    "let defs = svg.append(\"defs\");\n",
    "\n",
    "let filter = defs.append(\"filter\").attr(\"id\", \"gooeyCodeFilter\");\n",
    "\n",
    "filter.append(\"feGaussianBlur\")\n",
    "    .attr(\"in\", \"SourceGraphic\")\n",
    "    .attr(\"stdDeviation\", \"10\")\n",
    "    .attr(\"color-interpolation-filters\", \"sRGB\")\n",
    "    .attr(\"result\", \"blur\");\n",
    "\n",
    "filter.append(\"feColorMatrix\")\n",
    "    .attr(\"in\", \"blur\")\n",
    "    .attr(\"mode\", \"matrix\")\n",
    "    .attr(\"values\", \"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9\")\n",
    "    .attr(\"result\", \"gooey\");\n",
    "\n",
    "d3.select(\"#d3_target\")\n",
    "    .append(\"g\")\n",
    "    .style(\"filter\", \"url(#gooeyCodeFilter)\")\n",
    "    .classed(\"container\", true);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {
    "dotnet_interactive": {
     "language": "javascript"
    },
    "polyglot_notebook": {
     "kernelName": "javascript"
    }
   },
   "source": [
    "generate data and send it to javscript using the new command"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "var rnd = new Random();\n",
    "\n",
    "for(var i = 0; i < 10; i++){\n",
    "    await Task.Delay(1000);\n",
    "    var limit = rnd.Next(4,12);\n",
    "    var data = Enumerable.Range(1,limit).Select( t => rnd.Next(30, 80)).ToArray();\n",
    "    await Kernel.Root.SendAsync(new WidgetData(\"javascript\"){\n",
    "        Data = data\n",
    "    });\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "polyglot-notebook"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [
       "C#",
       "c#"
      ],
      "languageName": "C#",
      "name": "csharp"
     },
     {
      "aliases": [
       "F#",
       "f#"
      ],
      "languageName": "F#",
      "name": "fsharp"
     },
     {
      "aliases": [],
      "languageName": "HTML",
      "name": "html"
     },
     {
      "aliases": [
       "js"
      ],
      "languageName": "JavaScript",
      "name": "javascript"
     },
     {
      "aliases": [],
      "languageName": "KQL",
      "name": "kql"
     },
     {
      "aliases": [],
      "languageName": "Mermaid",
      "name": "mermaid"
     },
     {
      "aliases": [
       "powershell"
      ],
      "languageName": "PowerShell",
      "name": "pwsh"
     },
     {
      "aliases": [],
      "languageName": "SQL",
      "name": "sql"
     },
     {
      "aliases": [],
      "name": "value"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
